package cn.mothin.frame.help;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import cn.mothin.frame.core.interfaces.ISqlHelper;
import cn.mothin.frame.core.interfaces.sequence.ISerialNumberEngineer;
import cn.mothin.frame.core.interfaces.sequence.ISerialNumberQuery;
import cn.mothin.frame.util.SpringUtil;

@Component("51ff39dccaca7da0aa257319")
public class SerialNumber implements ISerialNumberEngineer {

	public static final String DEFINE_YEAR_4 = "${yyyy}";
	public static final String DEFINE_YEAR_2 = "${yy}";
	public static final String DEFINE_YEAR_MONTH = "${yyyyMM}";
	public static final String DEFINE_YEAR_MONTH_2 = "${yyMM}";
	// public static final String DEFINE_YEAR_QUARTER = "${yyyyQ}";
	// public static final String DEFINE_YEAR_QUARTER_2 = "${yyQ}";

	public static final String DEFINE_SERIAL_NUMBER = "${sn}";
	public static final String DEFINE_SERIAL_NUMBER_WIDTH_BEGIN = "${sn,";
	public static final String DEFINE_SERIAL_NUMBER_WIDTH_REGEX = "\\$\\{sn,(\\d+)\\}";
	public static final String DEFINE_CUSTOMER_SERIAL_NUMBER = "${csn}";

	@Autowired
	private ISqlHelper sqlHelper;

	private String querySerialNumber(String id) {
		List<ISerialNumberQuery> list = SpringUtil
				.getClassListWithInterface(ISerialNumberQuery.class);
		for (ISerialNumberQuery query : list) {
			String sn = query.querySerialNumber(id);
			if (sn != null) {
				return sn;
			}
		}
		return null;
	}

	private int queryCurrentNumber(String type, String id, String period) {
		List<Object> params=new ArrayList<Object>();
		
		String sql = "SELECT currentNumber FROM serial_number WHERE serialNumberTemplateId=?";
		params.add(type);
		if(id!=null){
			sql+=" AND subtype=?";
			params.add(id);
		}else{
			sql+=" AND subtype IS NULL";
		}
		if(period!=null){
			sql+=" AND period=?";
			params.add(period);
		}else{
			sql+=" AND period IS NULL";
		}
		List<Map<String,Object>> list = sqlHelper.queryForList(sql, params.toArray());
		if (list.size()==0) {
			return -1;
		}
		return (int)list.get(0).get("currentNumber");
	}

	private void saveOrUpdateSerialNumber(String type, String id,
			String period, int number) {
		List<Object> params=new ArrayList<Object>();
		
		String sql = "SELECT COUNT(id) FROM serial_number WHERE serialNumberTemplateId=?";
		params.add(type);
		if(id!=null){
			sql+=" AND subtype=?";
			params.add(id);
		}else{
			sql+=" AND subtype IS NULL";
		}
		if(period!=null){
			sql+=" AND period=?";
			params.add(period);
		}else{
			sql+=" AND period IS NULL";
		}
		long l = sqlHelper.queryCount(sql, params.toArray());
		if (l > 0) {
			List<Object> params2=new ArrayList<Object>();
			sql = "UPDATE serial_number SET currentNumber=? WHERE serialNumberTemplateId=?";
			params2.add(number);
			params2.add(type);
			if(id!=null){
				sql+=" AND subtype=?";
				params2.add(id);
			}else{
				sql+=" AND subtype IS NULL";
			}
			if(period!=null){
				sql+=" AND period=?";
				params2.add(period);
			}else{
				sql+=" AND period IS NULL";
			}
			sqlHelper.execute(sql, params2.toArray());
		} else {
			sql = "INSERT INTO serial_number(id,serialNumberTemplateId,subtype,period,currentNumber) VALUES(?,?,?,?,?)";
			sqlHelper.execute(sql, UniqueCode.make(), type, id, period, number);
		}
	}

	@Override
	public String makeSerialNumber(String type, String id) {
		// 根据type获取规则模板
		String sql = "SELECT template,initialNumber FROM serial_number_template WHERE id=?";
		List<Map<String, Object>> list = sqlHelper.queryForList(sql, type);
		if (list.size() > 0) {
			Map<String, Object> map = list.get(0);
			String template = map.get("template").toString();
			int initialNumber = (int) map.get("initialNumber");
			Date now = new Date(System.currentTimeMillis());
			SimpleDateFormat simpleDateFormat;
			String period = null;

			if (template.contains(DEFINE_YEAR_4)) {
				simpleDateFormat = new SimpleDateFormat("yyyy");
				period = simpleDateFormat.format(now);
				template = template.replace(DEFINE_YEAR_4, period);
			} else if (template.contains(DEFINE_YEAR_2)) {
				simpleDateFormat = new SimpleDateFormat("yy");
				period = simpleDateFormat.format(now);
				template = template.replace(DEFINE_YEAR_2, period);
			} else if (template.contains(DEFINE_YEAR_MONTH)) {
				simpleDateFormat = new SimpleDateFormat("yyyyMM");
				period = simpleDateFormat.format(now);
				template = template.replace(DEFINE_YEAR_MONTH, period);
			} else if (template.contains(DEFINE_YEAR_MONTH_2)) {
				simpleDateFormat = new SimpleDateFormat("yyMM");
				period = simpleDateFormat.format(now);
				template = template.replace(DEFINE_YEAR_MONTH_2, period);
			}

			if (template.contains(DEFINE_CUSTOMER_SERIAL_NUMBER)) {
				String csn = querySerialNumber(id);
				if (csn == null) {
					csn = "";
				}
				template = template.replace(DEFINE_CUSTOMER_SERIAL_NUMBER, csn);
			}

			int number = queryCurrentNumber(type, id, period);
			if (number == -1) {
				number = initialNumber;
			}
			if (template.contains(DEFINE_SERIAL_NUMBER)) {
				template = template.replace(DEFINE_SERIAL_NUMBER,
						Integer.toString(number));
			} else if (template.contains(DEFINE_SERIAL_NUMBER_WIDTH_BEGIN)) {
				Pattern pattern = Pattern
						.compile(DEFINE_SERIAL_NUMBER_WIDTH_REGEX);
				Matcher matcher = pattern.matcher(template);
				if (matcher.find()) {
					String length = matcher.group(1);
					template = matcher.replaceAll(String.format("%0" + length
							+ "d", number));

				}
			}
			saveOrUpdateSerialNumber(type, id, period, number + 1);
			return template;
		}
		return null;
	}
}
